#pragma once

#include <iostream>
#include <pthread.h>
#include <filesystem> //C++17
#include <string>
#include <memory>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <time.h>

namespace lyrics
{
    // 日志等级
    enum class LogLevel
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FETAL
    };
    std::string LogLevelToStr(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::WARNING:
            return "WARNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FETAL:
            return "FETAL";
        default:
            return "None";
        }
    }
    std::string GetCurrtime()
    {
        time_t timestamp = ::time(nullptr);
        struct tm curr;
        localtime_r(&timestamp,&curr);
        char buffer[1024];

        snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr.tm_year + 1900,
                 curr.tm_mon + 1,
                 curr.tm_mday,
                 curr.tm_hour,
                 curr.tm_min,
                 curr.tm_sec);
        return buffer;
    }
    const std::string Default_Path = "./log/";
    const std::string Default_Name = "Log.txt";

    // 策略模式
    class Strategy_Pattern
    {
    public:
        // 使用系统默认的析构函数
        virtual ~Strategy_Pattern() = default;
        // 纯虚函数，需要基类实现
        virtual void Log_refresh_mode(const std::string &message) = 0;
    };
    // 刷新到屏幕上
    class Refresh_to_screen : public Strategy_Pattern
    {
    public:
        Refresh_to_screen()
        {
            int n = pthread_mutex_init(&_mutex, nullptr);
        }
        ~Refresh_to_screen()
        {
            pthread_mutex_destroy(&_mutex);
        }
        void Log_refresh_mode(const std::string &message)
        {
            pthread_mutex_lock(&_mutex);
            std::cout << message << std::endl;
            pthread_mutex_unlock(&_mutex);
        }

    private:
        pthread_mutex_t _mutex;
    };
    // 刷新到文件中
    class Refresh_to_file : public Strategy_Pattern
    {
    public:
        // 初始化函数用于初始化
        Refresh_to_file(const std::string &Path = Default_Path, const std::string &Name = Default_Name)
            : _Default_Path(Path), _Default_Name(Name)
        {
            pthread_mutex_init(&_mutex, nullptr);
            pthread_mutex_lock(&_mutex);
            // 需要检查文件是否创建
            if (std::filesystem::exists(_Default_Path)) return;
            try
            {
                std::filesystem::create_directories(_Default_Path);
            }
            catch (std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << "\n";
            }
            pthread_mutex_unlock(&_mutex);
        }
        void Log_refresh_mode(const std::string &message)
        {
            pthread_mutex_lock(&_mutex);
            std::string log = _Default_Path + _Default_Name;
            std::ofstream out(log, std::ios::app);
            if (!out.is_open()) return;
            out << message << std::endl;
            out.close();
            pthread_mutex_unlock(&_mutex);
        }
        ~Refresh_to_file()
        {
            pthread_mutex_destroy(&_mutex);
        }

    private:
        pthread_mutex_t _mutex;
        std::string _Default_Path; // 默认路径
        std::string _Default_Name; // 默认文件名
    };
    // 日志类
    //
    class Log
    {
    public:
        class LogMessage
        {
        public:
            // 初始化信息
            LogMessage(std::string filename,LogLevel level,int line,Log &logger)
            :_filename(filename),_line(line),_loglevel(level),
            _currtime(GetCurrtime()),_pid(getpid()),_logger(logger)
            {      
                std::stringstream ssbuffer;
                ssbuffer << "[" << _currtime << "] "
                         << "[" << LogLevelToStr(_loglevel) << "] "
                         << "[" << _pid << "] "
                         << "[" << _filename << "] "
                         << "[" << _line << "] - ";
                _loginfo = ssbuffer.str();
            }
            template<class T>
            LogMessage& operator<<(const T& data)
            {
                std::stringstream ss;
                ss << data;
                _loginfo += ss.str();
                return *this;
            }
            ~LogMessage()
            {
                if(_logger._Strategy)
                {
                    _logger._Strategy->Log_refresh_mode(_loginfo);
                }
            }

        private:
            std::string _filename; // 文件名
            LogLevel _loglevel;    // 日志等级
            std::string _currtime; // 当前时间
            pid_t _pid;            // 进程pid
            int _line;             // 行号
            std::string _loginfo;  //完整的日志信息
            Log &_logger;          //日志
        };

    public:
        // 默认刷新方式
        Log()
        {
            // 刷新到屏幕上
            _Strategy = std::make_shared<Refresh_to_screen>();
        }
        //operator()重载----传递文件还有行号，构建临时对象返回拷贝
        LogMessage operator()(LogLevel level,const std::string filename,int line)
        {
            return LogMessage(filename,level,line,*this);
        }
        // 刷新到文件当中
        void RefreshToFile()
        {
            _Strategy = std::make_shared<Refresh_to_file>();
        }
        // 刷先到屏幕上
        void RefreshToScreen()
        {
            _Strategy = std::make_shared<Refresh_to_screen>();
        }
        ~Log() {}

    private:
        std::shared_ptr<Strategy_Pattern> _Strategy;
    };
    Log logger;
    #define LOG(Level) logger(Level, __FILE__, __LINE__)
}